home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 8
/
Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso
/
Aminet
/
dev
/
c
/
Asyncio.lha
/
asyncio.doc
next >
Wrap
Text File
|
1995-08-12
|
16KB
|
408 lines
TABLE OF CONTENTS
asyncio/--changes---
asyncio/--background--
asyncio/CloseAsync
asyncio/OpenAsync
asyncio/ReadAsync
asyncio/ReadCharAsync
asyncio/SeekAsync
asyncio/WriteAsync
asyncio/WriteCharAsync
asyncio/--changes-- asyncio/--changes--
This version of the package (called release 3) is dated 12-Aug-95. All
changes herein were made by Magnus Holmgren (with some inspiration from the
asyncio code found in the AIFF datatype, by Olaf `Olsen' Barthel). I've
been in contact with Martin Taillefer, and he is aware of this release.
However, he is not informed about the actual details of the changes in the
code. Thus, any comments about the code (especially the changes) should not
be sent to him.
This version includes a couple of enhancements (most from the AIFF sources)
and a couple of bugfixes to SeekAsync():
- SeekAsync() is now not unecessarely slow when doing some "kinds" of
read-mode seeks (typically when seeking after some small amount of
initial read). The problem was that it usually only considered the
newly arrived buffer, not both buffers. This could make it discard both
buffers, and restart reading, although one of the buffers already had
the needed data. Note that the kind of seeks that caused the above
problem may still seem to be somewhat slow, since the code must wait
for both buffers to be loaded. This cannot (easily) be avoided.
- SeekAsync() doesn't cause the read buffer to contain garbage after
certain seeks any more. The problem was that ReadAsync() would read
from the wrong buffer (the one currently being loaded). This made the
files seem to contain garbage. This happened when the seek location
was within the newly arrived buffer.
- The code package is now supplied as a link library, rather than a
single source module. The internal functions labeled "AS_#?" are
private and should not be called directly by the application.
- A few minor "cosmetic" changes were done, to either make the code more
readable, or to make it slightly smaller.
- Include file restructured a little (a public and a private part).
- OpenAsync() now offers some new "options" (all from the AIFF code by
Olaf Barthel):
1) Opening a file from an already open filehandle is now possible.
2) A "no externals" version may be compiled, that doesn't require any
external variables to be available.
3) Each of the buffers will now be roughly bufferSize / 2 bytes large,
rather than bufferSize bytes.
4) If there isn't enough memory for the requested buffer size, the code
will try with smaller buffers (still properly "aligned") before
giving up.
The code was compiled using DICE 3.0. SAS/C or GCC should be able to
compile it as well, without any changes (although I haven't tested this).
I didn't include any makefile, since I don't use one anyway! ;) Instead I
use the LbMake utility in the DICE package. The Lib.Def file contains the
definitions for the link library.
asyncio/--background-- asyncio/--background--
This documentation and source code was written by Martin Taillefer. This
version of the package is dated 16-Feb-94. This version contains several
bug fixes over previous versions. The most important changes are:
- SeekAsync() now consistently works. It was getting confused when called
multiple times in a row with no intervening IO.
- WriteAsync() would produce garbage in the destination file if it had
to bring up a "Disk is full" requester, and the user freed some room on
the disk and selected "Retry".
Reading and writing data is crucial to most applications and is in many cases a
major bottleneck. Using the AmigaDOS' sophisticated file system architecture
can help reduce, and sometimes eliminate, the time spent waiting for IO to
complete. This package offers a few small routines that can greatly improve an
application's IO performance.
Normally, an application processes a file in a manner similar to the following:
1 - Open the file
2 - Read some data
3 - Process data just read
4 - Repeat steps 2 and 3 until all data is processed
5 - Close file
Although the above sequence works fine, it doesn't make full use of the Amiga's
multitasking abilities. Step 2 in the above can become a serious bottleneck.
Whenever the application needs some data by using the DOS Read() function,
AmigaDOS has to put that task to sleep, and initiate a request to the file
system to have it fetch the data. The file system then starts up the disk
hardware and reads the data. Once the data is read, the application is woken up
and can start processing the data just read.
The point to note in the above paragraph is that when the file system is
reading data from disk, the application is asleep. Wouldn't it be nice if the
application could keep running while data is being fetched for it?
Most Amiga hard drives make use of DMA (Direct Memory Access). DMA enables a
hard drive to transfer data to memory _at the same time_ as the CPU does some
work. This parallelism is what makes the set of accompanying routines so
efficient. They exploit the fact that data can be transfered to memory while
the application is busy processing other data.
Using the asynchronous IO routines, an application's IO happens like this:
1 - Open the file, ask the file system to start reading ahead
2 - Read some data, ask the file system to read more data
3 - Process data
4 - Repeat steps 2 and 3 until all data is processed
5 - Close file
Immediately after opening the file, a request is sent to the file system to get
it reading data in the background. By the time the application gets around to
reading the first byte of data, it is likely already in memory. That means the
application doesn't need to wait and can start processing the data. As soon as
the application starts processing data from the file, a second request is sent
out to the file system to fill up a second buffer. Once the application is done
processing the first buffer, it starts processing the second one. When this
happens, the file system starts filling up the first buffer again with new
data. This process continues until all data has been read.
The whole technique is known as "double-buffered asynchronous IO" since it uses
two buffers, and happens in the background (asynchronously).
The set of functions presented below offers high-performance IO using the
technique described above. The interface is very similar to standard AmigaDOS
files. These routines enable full asynchronous read/write of any file.
asyncio/CloseAsync asyncio/CloseAsync
NAME
CloseAsync -- close an async file.
SYNOPSIS
success = CloseAsync(file);
LONG CloseAsync(struct AsyncFile *);
FUNCTION
Closes a file, flushing any pending writes. Once this call has been
made, the file can no longer be accessed.
INPUTS
file - the file to close. May be NULL, in which case this function
returns -1 and sets the IoErr() code to ERROR_INVALID_LOCK.
If the "no externals" version is used, then a NULL will not
set IoErr() (not possible).
RESULT
result - < 0 for an error, >= 0 for success. Indicates whether closing
the file worked or not. If the file was opened in read-mode,
then this call will always work. In case of error,
dos.library/IoErr() can give more information.
SEE ALSO
OpenAsync(), dos.library/Close()
asyncio/OpenAsync asyncio/OpenAsync
NAME
OpenAsync -- open a file for asynchronous IO.
SYNOPSIS
file = OpenAsync(fileName, accessMode, bufferSize
[, sysbase, dosbase ] );
struct AsyncFile OpenAsync(const STRPTR, UBYTE, LONG
[, struct ExecBase *, struct DosLibrary * ] );
file = OpenAsyncFromFH(handle, accessMode, bufferSize
[, sysbase, dosbase ] );
struct AsyncFile OpenAsyncFromFH(BPTR, UBYTE, LONG
[, struct ExecBase *, struct DosLibrary * ] );
FUNCTION
The named file is opened and an async file handle returned. If the
accessMode is MODE_READ, an existing file is opened for reading.
If accessMode is MODE_WRITE, a new file is created for writing. If
a file of the same name already exists, it is first deleted. If
accessMode is MODE_APPEND, an existing file is prepared for writing.
Data written is added to the end of the file. If the file does not
exists, it is created.
'fileName' is a filename and CANNOT be a window specification such as
CON: or RAW:, or "*"
'bufferSize' specifies the size of the IO buffer to use. There are
in fact two buffers allocated, each of roughly (bufferSize/2) bytes
in size. The actual buffer size use can vary slightly as the size
is rounded to speed up DMA.
If the file cannot be opened for any reason, the value returned
will be NULL, and a secondary error code will be available by
calling the routine dos.library/IoErr().
INPUTS
name - name of the file to open, cannot be a window specification.
handle - file handle to use async io on. The file pointer must be
located at the start of the file, and you may not access
it during the life of the AsyncFile handle. After CloseAsync,
you are responsible of closing the file.
accessMode - one of MODE_READ, MODE_WRITE, or MODE_APPEND
bufferSize - size of IO buffer to use. 8192 is recommended as it
provides very good performance for relatively little
memory.
sysbase - Library base needed for the "no externals" version of the
library.
dosbase - Library base, as sysbase.
RESULTS
file - an async file handle or NULL for failure. You should not access
the fields in the AsyncFile structure, these are private to the
async IO routines. In case of failure, dos.library/IoErr() can
give more information.
NOTES (by MH)
Although stated that CON:, RAW:, or "*" cannot be used as the file
name, tests indicates that the "Console:" volume is safe to use for
writing at least. No guarantees though.
SEE ALSO
CloseAsync(), dos.library/Open()
asyncio/ReadAsync asyncio/ReadAsync
NAME
ReadAsync -- read bytes from an async file.
SYNOPSIS
actualLength = ReadAsync(file, buffer, numBytes);
LONG ReadAsync(struct AsyncFile *, APTR, LONG);
FUNCTION
This function reads bytes of information from an opened async file
into the buffer given. 'numBytes' is the number of bytes to read from
the file.
The value returned is the length of the information actually read.
So, when 'actualLength' is greater than zero, the value of
'actualLength' is the the number of characters read. Usually
ReadAsync() will try to fill up your buffer before returning. A value
of zero means that end-of-file has been reached. Errors are indicated
by a value of -1.
INPUTS
file - opened file to read, as obtained from OpenAsync()
buffer - buffer where to put bytes read
numBytes - number of bytes to read into buffer
RESULT
actualLength - actual number of bytes read, or -1 if an error. In
case of error, dos.library/IoErr() can give more
information.
SEE ALSO
OpenAsync(), CloseAsync(), ReadCharAsync(), WriteAsync(),
dos.library/Read()
asyncio/ReadCharAsync asyncio/ReadCharAsync
NAME
ReadCharAsync -- read a single byte from an async file.
SYNOPSIS
byte = ReadCharAsync(file);
LONG ReadCharAsync(struct AsyncFile *);
FUNCTION
This function reads a single byte from an async file. The byte is
returned, or -1 if there was an error reading, or if the end-of-file
was reached.
INPUTS
file - opened file to read from, as obtained from OpenAsync()
RESULT
byte - the byte read, or -1 if no byte was read. In case of error,
dos.library/IoErr() can give more information. If IoErr()
returns 0, it means end-of-file was reached. Any other value
indicates an error.
SEE ALSO
OpenAsync(), CloseAsync(), ReadAsync(), WriteCharAsync()
dos.library/Read()
asyncio/SeekAsync asyncio/SeekAsync
NAME
SeekAsync -- set the current position for reading or writing within
an async file.
SYNOPSIS
oldPosition = SeekAsync(file, position, mode);
LONG SeekAsync(struct AsyncFile *, LONG, BYTE);
FUNCTION
SeekAsync() sets the read/write cursor for the file 'file' to the
position 'position'. This position is used by the various read/write
functions as the place to start reading or writing. The result is the
current absolute position in the file, or -1 if an error occurs, in
which case dos.library/IoErr() can be used to find more information.
'mode' can be MODE_START, MODE_CURRENT or MODE_END. It is used to
specify the relative start position. For example, 20 from current
is a position 20 bytes forward from current, -20 is 20 bytes back
from current.
To find out what the current position within a file is, simply seek
zero from current.
INPUTS
file - an opened async file, as obtained from OpenAsync()
position - the place where to move the read/write cursor
mode - the mode for the position, one of MODE_START, MODE_CURRENT,
or MODE_END.
RESULT
oldPosition - the previous position of the read/write cursor, or -1
if an error occurs. In case of error, dos.library/IoErr()
can give more information.
NOTES (by MH)
If you seek after having read only a few bytes, the function must
wait for both buffers to be loaded, before the seek can be done.
This can cause small delays. Note that the above case isn't the
only one, but the typical one.
SEE ALSO
OpenAsync(), CloseAsync(), ReadAsync(), WriteAsync(),
dos.library/Seek()
asyncio/WriteAsync asyncio/WriteAsync
NAME
WriteAsync -- write data to an async file.
SYNOPSIS
actualLength = WriteAsync(file, buffer, numBytes);
LONG WriteAsync(struct AsyncFile *, APTR, LONG);
FUNCTION
WriteAsync() writes bytes of data to an opened async file. 'numBytes'
indicates the number of bytes of data to be transferred. 'buffer'
points to the data to write. The value returned is the length of
information actually written. So, when 'numBytes' is greater than
zero, the value of 'numBytes' is the number of characters written.
Errors are indicated by a return value of -1.
INPUTS
file - an opened file, as obtained from OpenAsync()
buffer - address of data to write
numBytes - number of bytes to write to the file
RESULT
actualLength - number of bytes written, or -1 if error. In case
of error, dos.library/IoErr() can give more
information.
SEE ALSO
OpenAsync(), CloseAsync(), ReadAsync(), WriteCharAsync(),
dos.library/Write()
asyncio/WriteCharAsync asyncio/WriteCharAsync
NAME
WriteCharAsync -- write a single byte to an async file.
SYNOPSIS
result = WriteCharAsync(file, byte);
LONG WriteCharAsync(struct AsyncFile *, UBYTE);
FUNCTION
This function writes a single byte to an async file.
INPUTS
file - an opened async file, as obtained from OpenAsync()
byte - byte of data to add to the file
RESULT
result - 1 if the byte was written, -1 if there was an error. In
case of error, dos.library/IoErr() can give more information.
SEE ALSO
OpenAsync(), CloseAsync(), ReadAsync(), WriteAsync(),
dos.library/Write()